#include "crossline.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>

// 在windows上，msvc这种编译器有些函数名称不一致
#ifdef _WIN32
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif

// 你可以忽视这个region
// 我只是为了实现trim一个字符串的功能。。。
#pragma region Util
/*
** Auxiliary function to skip white spaces
*/
int is_white_space(char c)
{
    return (c == ' ' || c == '\t' || c == '\n');
}

/*
** Iterate through the white spaces at the beginning of the string
*/
int get_first_position(char const *str)
{
    int i = 0;
    while (is_white_space(str[i]))
    {
        i += 1;
    }
    return (i);
}

/*
** Get the length of a string
*/
int get_str_len(char const *str)
{
    int len = 0;
    while (str[len] != '\0')
    {
        len += 1;
    }
    return (len);
}

/*
** Find the last position in a string that is not a white space
*/
int get_last_position(char const *str)
{
    int i = get_str_len(str) - 1;
    while (is_white_space(str[i]))
    {
        i -= 1;
    }
    return (i);
}

/*
** Returns the correct length of a trimmed string
*/

int get_trim_len(char const *str)
{
    return (get_last_position(str) - get_first_position(str));
}

/*
** Allocates a new string with removed whitespace characters from the beginning of the source string `str`
*/
char *strtrim(char const *str)
{
    char *trim = NULL;
    int i, len, start, end;
    if (str != NULL)
    {
        i = 0;
        len = get_trim_len(str) + 1;
        trim = (char *)malloc(len);
        start = get_first_position(str);
        while (i < len)
        {
            trim[i] = str[start];
            i += 1;
            start += 1;
        }
        trim[i] = '\0';
    }
    return trim;
}
#pragma endregion

// auto-complete keyword / give hints
struct keyword
{
    const char *word;           // keyword
    crossline_color_e w_color;  // word_color
    const char *help;           // help
    crossline_color_e he_color; // help_color
    const char *hint;           // hint
    crossline_color_e hi_color; // hint_color

    keyword(const char *word = nullptr, crossline_color_e w_color = CROSSLINE_FGCOLOR_DEFAULT, const char *help = nullptr, crossline_color_e he_color = CROSSLINE_FGCOLOR_DEFAULT, const char *hint = nullptr, crossline_color_e hi_color = CROSSLINE_FGCOLOR_DEFAULT)
    {
        this->word = word;
        this->w_color = w_color;
        this->help = help;
        this->he_color = he_color;
        this->hint = hint;
        this->hi_color = hi_color;
    }
};

// 这里这些定义是来自我的另一个项目Basic编译器
// 随便挑了几个颜色不一样的
const keyword keywords[] = {
    {(const char *)"VAR", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char *)"Declare or Assign a variable", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char *)"VAR IDENTIFIER = expr", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"IF", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_MAGENTA), (const char *)"IF control statement", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char *)"IF <condition> THEN <do sth>", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"NOT", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char *)"logic operator NOT", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"TRUE", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char *)"bool TRUE", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"FALSE", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_BLUE), (const char *)"bool FALSE", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"IS_NUM", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char *)"Check if given value is Number", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char *)"IS_NUM(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
    {(const char *)"IS_STR", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_YELLOW), (const char *)"Check if given value is String", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN), (const char *)"IS_STR(value)", (crossline_color_e)(CROSSLINE_FGCOLOR_BRIGHT | CROSSLINE_FGCOLOR_GREEN)},
};

// 这是Crossline提供的API，实现自定义自动补全一定要实现该接口
void completion_hook(const char *buf, crossline_completions_t *pCompletion)
{
    // 注意这里的实现只能匹配一个词
    // 如果想要在一行输入内，多次使用tab补全
    // 请参考我在Basic编译器中的实现
    // https://gitee.com/Morphlng/basic/blob/master/src/Common/utils.cpp

    const char *input = strtrim(buf);

    for (const keyword &p : keywords)
    {
        if (p.word == nullptr)
            break;

        if (strncasecmp(input, p.word, strlen(input)) == 0)
        {
            // 如果全字匹配，则显示“提示”
            if (strlen(input) == strlen(p.word))
            {
                if (p.hint != nullptr)
                    crossline_hints_set_color(pCompletion, p.hint, p.hi_color);
                break;
            }
            // 否则去找“匹配项”
            crossline_completion_add_color(pCompletion, p.word, p.w_color, p.help, p.he_color);
        }
    }
}

// 在正式使用之前，你需要把自定义的内容“挂载”上去
void init()
{
    // 绑定你的自动补全函数
    crossline_completion_register(completion_hook);
    // 输入历史存储位置，下一次打开将自动读取
    crossline_history_load("history.txt");
    // 默认提示符颜色
    crossline_prompt_color_set(CROSSLINE_FGCOLOR_CYAN);
}

int main()
{
    init();

    // 你需要一个足够大的地方去存储每一次输入
    char line[256];
    while (crossline_readline("input > ", line, sizeof(line)) && (strncmp(line, "exit", 4)))
    {
        if (line == "")
            continue;
        else
        {
            printf("input is %s\n", line);
        }
    }
}

// g++ crossline.cpp example_by_morphlng.cpp -O3 -o main